home *** CD-ROM | disk | FTP | other *** search
- /*
- LevelMeter Visual Plugin Example
-
- Sample visual plugin to demonstrate MacAmp visual plugin API and additional tricks,
- including access of the plugin resource fork, initializing the plugin info structure on
- startup and more.
-
- You can use any portions of this code freely in your plugins without any restrictions.
-
- By: Slava Karpenko (slava@macamp.com) 9/2/98
- @soft
-
- */
-
- #include "visual.h"
-
- // Some useful defines.
- #define MIN(a,b) (((a)<(b))?(a):(b))
- #define MAX(a,b) (((a)>(b))?(a):(b))
- #define ABS(a) ((a)<0?-(a):(a))
-
- // This is the gPlugInfo block - a place where MacAmp gets initial information about your plugin.
- // Make sure to set the fragment's entry point to gPlugInfo to make it accessible for the MacAmp routines.
-
- VPInfoBlock gPlugInfo =
- {
- VP_API_VERSION, // Should be always VP_API_VERSION
- plugVisual, // Should be always plugVisual (otherwise what are we doing here? =)
-
- nil, // We have no flags
- nil, // We have no global refcon.
- "\pLevelMeter", // What's our name to display in the Plugins menu?
-
- // Function pointers. Use nil if you don't use something.
- PlugInitialize,
- PlugTerminate,
- PlugProcess,
- PlugMacEvent,
- PlugKeyDown, // (unused in this example)
- PlugIdle, // (unused in this example)
- PlugSettings, // (unused in this example)
- PlugAbout
- };
-
- // These are globals.
- static long ticks; // tick count variable to keep some sort of synch.
- static short left; // left and right channel values (0<=x<=20)
- static short right;
- static short refnum; // plugin resource fork refnum
-
- // dirty hack.
- static Rect gScreenBounds = { 0, 0, 624, 832 };
-
- // Other function prototypes
- void ProcessMP3(short chan, const double* stream);
- void ProcessMP2(short chan, const double* stream);
- void DrawMeters(WindowPtr wind);
- OSErr PlugLoadMyself(void);
- void PlugUnloadMyself(void);
-
- /*
- PlugLoadMyself
-
- Called when your plugin fragment is loaded in memory. You may wish to change gPlugInfo fields here, or
- do something else like opening your global preferences. Take a look at the PPC Linker panel in the target settings
- to get an idea how it's done.
-
- */
- OSErr PlugLoadMyself(void)
- {
- return noErr;
- }
-
- /*
- PlugUnloadMyself
-
- Called when MacAmp is about to quit and dispose all plugins. Dispose any global stuff you allocated in PlugLoadMyself
- etc.
-
- */
- void PlugUnloadMyself(void)
- {
- return;
- }
-
- /*
- PlugInitialize
-
- Called every time use selects your plugin from the Plugins menu. You need to allocate and display a window here,
- init your variables, and do whatever you want, like set the refnum if you need it.
-
- This function uses FSSpec to itself that MacAmp provides to it to gain access to its resource fork.
-
- Other than that, everything is hard-coded and is definitly not an example of good programming =P
- */
- OSErr PlugInitialize(WindowPtr* window, FSSpecPtr file, UInt32*)
- {
- Rect bounds = { 40, 10, 49, 70 }; // guess what this is, it's window coordinates. Yuck. =)
- GrafPtr port;
-
- GetPort(&port);
-
- // create a new window with floating look as included in MacOS 7.6+ (WDEF id 124)
- *window = NewCWindow(nil,&bounds,"\p",true,1985,(WindowPtr)-1,true,nil);
-
- if (!*window)
- return visNoMemory;
-
- SetPort(*window);
- BackColor(blackColor);
- PenSize(1, 4);
- ForeColor(greenColor);
- SetPort(port);
-
- // init our variables.
- left = right = 0;
- ticks = TickCount();
-
- // draw zeroes initially
- DrawMeters(*window);
-
- // Open our resource fork and save the refnum for closing it (we are a well-behaved plugin, right? ;)
- refnum = FSpOpenResFile(file, fsRdPerm);
-
- return visNoErr;
- }
-
- /*
- PlugTerminate
-
- Called when user deselects your plugin, MacAmp quits or in the case if you have passed visTerminate/visNoMemory error.
- You should dispose your window here & clean up the mess.
- */
- OSErr PlugTerminate(WindowPtr window, UInt32*)
- {
- if (window != nil)
- DisposeWindow(window);
-
- // Close our resource fork.
- if (refnum != -1)
- FSClose(refnum);
-
- return visNoErr;
- }
-
- /*
- PlugProcess
-
- The heart of the visual plugin. It means your plugin needs to analyze the stream and display whatever you want.
-
- chan is the number of channels.
- stream is the sound data, which has the size of [2][32][dataSize]. For now dataSize==18 means layer III files,
- dataSize == 36 means layer II files. Sound data is separated by channels, so stream[0] would be left, and stream[1] -
- right channel.
-
- You should never ever modify the contents of the stream pointer. Doing so will affect the playback.
- [On the other hand, if you know what you're doing, you CAN modify the data stream. Doing so will change the sound.
- So with a little knowledge you can turn a visual plugin into a sound plugin (make a new equalizer ;)]
- */
- OSErr PlugProcess(WindowPtr window, short chan, const double* stream, short dataSize, UInt32*)
- {
- if (TickCount() - ticks > 1)
- {
- if (dataSize == 18)
- ProcessMP3(chan, stream);
- else
- ProcessMP2(chan, stream);
-
- DrawMeters(window);
-
- left--;
- right--;
- ticks = TickCount();
- }
-
- return visNoErr;
- }
-
- /*
- PlugMacEvent
-
- Process a mac event that is related to the window (activate/deactivate, update, mouseDown).
-
- You can do whatever you want, but remember that if you don't handle update events, that will screw up the whole
- MacAmp window update process.
- */
- OSErr PlugMacEvent(WindowPtr window, EventRecord* event, UInt32*)
- {
- OSErr result = visNoErr;
- switch (event->what)
- {
- case updateEvt:
- BeginUpdate(window);
- DrawMeters(window);
- EndUpdate(window);
- break;
-
- case mouseDown:
- {
- WindowPtr wind;
- short thePart = FindWindow(event->where, &wind);
- switch (thePart)
- {
- case inDrag:
- // ugly hack. it shoulkd be qd.screenBits.bounds.
- DragWindow(wind, event->where, &gScreenBounds);
- break;
-
- case inGoAway:
- if (TrackGoAway(wind, event->where))
- result = visTerminate; // if user clicked the close box, shut ourself down.
- break;
-
- case inContent:
- // hehe, max out everything
- left = right = 20;
- DrawMeters(wind);
- break;
- }
-
- }
- break;
-
- default:
- break;
- }
- return result;
- }
-
- /*
- PlugAbout
-
- Called when a user selects "About the Plugin" from the menu. You should display some sort of about box,
- do some sort of an effect or whatever you feel like it.
- */
- OSErr PlugAbout(WindowPtr, UInt32*)
- {
- NoteAlert(1234, nil);
- return visNoErr;
- }
-
- /*
- PlugIdle
-
- Called whenever MacAmp gets some spare time. It's a good place to decrement your values, draw the stuff etc.
-
- Called only if flagGetIdle is set.
- */
- OSErr PlugIdle(WindowPtr window, UInt32* refcon)
- {
- #pragma unused (window, refcon)
- return visNoErr;
- }
-
- /*
- PlugKeyDown
-
- Called when a user presses a button, and after it was processed by MacAmp. Keep in mind that no matter if it
- was processed by MacAmp or not, your plug still gets it. So if you want tto have some keyboard control, try to
- use unused keys.
-
- Called only if flagGetKeyDown is set.
- */
- OSErr PlugKeyDown(WindowPtr window, char key, short modifiers, UInt32* refcon)
- {
- #pragma unused (window, key, modifiers, refcon)
- return visNoErr;
- }
-
- /*
- PlugSettings
-
- Called when user selects your plugin from the Settings submenu. Only used if you have declared that
- you support settings (flagHasSettings is set).
-
- You should display the settings dialog here, or do whateverr you feel like. =) Just remember that when user
- chooses settings (s)he expects some interactino with the plugin, like the dialog or like that.
- */
- OSErr PlugSettings(WindowPtr window, UInt32* refcon)
- {
- #pragma unused (window, refcon)
- return visNoErr;
- }
-
- // The following two functions are examples of analyzing the data stream.
- void ProcessMP3(short chan, const double* stream)
- {
- int z;
-
- double sum1 = 0.0;
- double sum2 = 0.0;
-
- if (chan == 2)
- {
- for (z = 1; z < 20; z ++)
- sum1 += stream[z];
- for (z = 1; z < 20; z ++)
- sum2 += stream[32*18+z];
- } else {
- for (z = 1; z < 20; z ++)
- sum1 += stream[z];
- sum2 = sum1;
- }
-
- sum1 = ABS(sum1) * 20.0;
- sum1 = MIN(20.0, MAX(0.0, sum1));
- left = MAX(left, sum1);
-
- sum2 = ABS(sum2) * 20.0;
- sum2 = MIN(20.0, MAX(0.0, sum2));
- right = MAX(right, sum2);
- }
-
- void ProcessMP2(short chan, const double* stream)
- {
- short z;
-
- double sum1 = 0.0;
- double sum2 = 0.0;
-
- if (chan == 2)
- {
- for (z = 0; z < 20; z ++)
- sum1 += stream[z];
- for (z = 0; z < 20; z ++)
- sum2 += stream[32*36+z];
- }
- else
- {
- for (z = 0; z < 20; z ++)
- sum1 += stream[z];
- sum2 = sum1;
- }
-
- sum1 = ABS(sum1) * 10;
- sum1 = MIN(20.0, MAX(0.0, sum1));
- left = MAX(left, sum1);
-
- sum2 = ABS(sum2) * 10;
- sum2 = MIN(20.0, MAX(0.0, sum2));
- right = MAX(right, sum2);
- }
-
- // And this is a really simple function that draws the meter bars.
- void DrawMeters(WindowPtr wind)
- {
- GrafPtr oldPort;
-
- GetPort(&oldPort);
- SetPort(wind);
- EraseRect(&wind->portRect);
- MoveTo(0,0);
- Line(left * 3, 0);
- MoveTo(0, 5);
- Line(right * 3, 0);
-
- SetPort(oldPort);
- }